<?php
/*
Aurus CMS - free OOP CMS
Copyright (C) 2010  Nestor Yanchuk

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
final class Factory {
	private static $self = null;
	private static $instances = array();
	private static $instancesSelf = array();

	/**
	 * Factory::get()
	 * 
	 * @param string $class
	 * @return $class
	 */
	public static function get($class) {
		if (isset(self::$instancesSelf[$class])) {
			return self::$instancesSelf[$class];
		} else {
			return self::$instancesSelf[$class] = new self($class);
		}
	}

	/**
	 * Factory::runStatic()
	 * 
	 * @param mixed $class
	 * @param mixed $method
	 * @return
	 */
	public static function runStatic($class, $method) {
		if (!class_exists($class)) {
			error('Class ' . $class . ' not found!');
		}

		Event::runEvent('before_' . callback_to_string(array($class,$method)) );
		if ($ret = call_user_func( array($class,$method)) ) {
			$ret = filter( $ret, callback_to_string(array($class,$method)) );
		}
		Event::runEvent('after_' . callback_to_string(array($class,$method)) );
		return $ret;
	}

	/**
	 * Factory::initClass()
	 * 
	 * @param mixed $className
	 * @return
	 */
	private static function initClass($className) {
		if (!isset(self::$instances[$className])) {
			self::$instances[$className] = new $className;
		}
	}

	///end of static part, start of private part
	private $workClass = null;
	/**
	 * Factory::__construct()
	 * 
	 * @param mixed $class
	 * @return
	 */
	public function __construct($class) {
		self::initClass($class);
		$this->workClass = $class;
	}

	function __call($methodName, $arguments) {
		//print($this->workClass.'->'.$methodName.'(\''.implode('\', \'',$arguments).'\');<br>');

		if (!method_exists(self::$instances[$this->workClass], $methodName)) {
			error('Call to undefined method ' . $this->workClass . '::' . $methodName . '()');
		}

		return $this->runFunc($this->workClass, $methodName, $arguments);
	}

	function __get($argName) {
		return self::$instances[$this->workClass]->$argName;
	}
	function __set($argName,$val) {
		self::$instances[$this->workClass]->$argName = $val;
	}


	/**
	 * Factory::runFunc()
	 * 
	 * @param mixed $class
	 * @param mixed $method
	 * @param mixed $arguments
	 * @return
	 */
	private function runFunc($class, $method, $arguments) {
		Event::runEvent('before_' . callback_to_string(array($class,$method)) );
		//		$ret = filter($this->_run( array(self::$instances[$class], $method), $arguments), callback_to_string(array($class,$method)) );
		if ($ret = $this->_run( array(self::$instances[$class], $method), $arguments) ) {
			$ret = filter($ret, callback_to_string(array($class,$method)) );
		}
		Event::runEvent('after_' . callback_to_string(array($class,$method)) );
		return $ret;
	}

	private static function _run($func, $arguments = array()) {
		if (!is_callable($func)) error('Function "'.callback_to_string($func).'" is not callable');
		return call_user_func_array($func, $arguments);
	}

	public function getDirect(){
		return self::$instances[$this->workClass];
	}
}

